package cc.shacocloud.mirage.restful;

import cc.shacocloud.mirage.restful.bind.annotation.RequestMapping;
import cc.shacocloud.mirage.utils.Utils;
import cc.shacocloud.mirage.utils.annotation.AnnotatedElementUtils;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 抽象的请求映射处理器映射
 */
public abstract class AbstractRequestMappingHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
    
    private static final String PATH_SEPARATOR = "/";
    
    private static final Map<Class<?>, RequestMappingInfo> PATH_PREFIX_MAP = new HashMap<>();
    
    private static final RequestMappingInfo EMPTY = RequestMappingInfo.builder().paths(new String[]{""}).build();
    
    @Nullable
    @Override
    protected RequestMappingInfo getMappingInfoForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo classRequestMapping = PATH_PREFIX_MAP.computeIfAbsent(handlerType, this::getClassRequestMapping);
        return createRequestMappingInfo(method, classRequestMapping);
    }
    
    /**
     * 获取类级别的请求映射
     *
     * @param handlerType 处理器类型
     * @return 路径前缀
     */
    protected RequestMappingInfo getClassRequestMapping(Class<?> handlerType) {
        RequestMappingInfo mappingInfo = createRequestMappingInfo(handlerType, EMPTY);
        if (mappingInfo != null) {
            String[] paths = mappingInfo.getPaths();
            if (paths.length > 1) {
                throw new IllegalArgumentException("类级别的 @RequestMapping 注解不支持多个路径：" + handlerType.getName());
            }
            return mappingInfo;
        }
        
        return EMPTY;
    }
    
    /**
     * 创建请求映射信息
     */
    @Nullable
    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element, RequestMappingInfo classRequestMapping) {
        RequestMapping requestMapping = AnnotatedElementUtils.getAnnotation(element, RequestMapping.class);
        return requestMapping != null ? createRequestMappingInfo(requestMapping, classRequestMapping) : null;
    }
    
    /**
     * 创建 {@link RequestMappingInfo} 从提供 {@link RequestMapping} 注解中
     */
    protected RequestMappingInfo createRequestMappingInfo(RequestMapping requestMapping,
                                                          RequestMappingInfo classRequestMapping) {
        String prefix;
        if (Objects.isNull(classRequestMapping.getPaths()) || classRequestMapping.getPaths().length == 0) {
            prefix = "";
        } else {
            prefix = classRequestMapping.getPaths()[0];
        }
        
        String[] paths = requestMapping.path();
        if (Objects.isNull(paths) || paths.length == 0) {
            paths = new String[]{""};
        }
        
        return RequestMappingInfo.builder()
                .pathPatterns(requestMapping.patterns())
                .paths(Arrays.stream(paths).map(p -> mergePath(prefix, p)).toArray(String[]::new))
                .methods(requestMapping.method())
                .consumes(Utils.nullOrDefault(requestMapping.consumes(), classRequestMapping::getConsumes))
                .produces(Utils.nullOrDefault(requestMapping.produces(), classRequestMapping::getProduces))
                .build();
    }
    
    /**
     * 合并路径
     */
    private String mergePath(String prefix, String path) {
        if (prefix == null || prefix.isEmpty())
            return path.startsWith(PATH_SEPARATOR) ? path : PATH_SEPARATOR + path;
        
        prefix = prefix.startsWith(PATH_SEPARATOR) ? prefix : PATH_SEPARATOR + prefix;
        
        if (path.equals("")) return prefix;
        
        boolean p1 = prefix.endsWith(PATH_SEPARATOR);
        boolean p2 = path.startsWith(PATH_SEPARATOR);
        if (p1 && p2) {
            path = path.substring(PATH_SEPARATOR.length());
        } else if (!p1 && !p2) {
            path = PATH_SEPARATOR + path;
        }
        return prefix + path;
    }
}
